package org.timemachine.classloader;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipException;

public class TimeMachineClassLoader extends URLClassLoader {
	
	private Vector<Class<?>> classes = new Vector<Class<?>>(); //used to cache already defined classes  
 
    private static URL[] makeUrls(File file) throws MalformedURLException {
        List<URL> urls = new ArrayList<URL>();
        urls.add(file.toURI().toURL());
        File[] jarFilesAndDirs = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return dir.isDirectory() || name.endsWith(".jar");
            }
        });
        if (jarFilesAndDirs != null) {
            for (File jarOrDir : jarFilesAndDirs) {
                if (jarOrDir.isDirectory()) {
                    urls.addAll(Arrays.asList(makeUrls(jarOrDir)));
                } else {
                    urls.add(jarOrDir.toURI().toURL());
                }
            }
        }
        return urls.toArray(new URL[urls.size()]);
    }
    
    public void loadClasses() throws IOException, ClassNotFoundException{
    	for (URL url : getURLs()) {
			File file = new File(url.getFile());
			if(file.isDirectory()){
                continue;
            }
			
			//if (file.getName().endsWith(".jar")) {
			//	loadFromJar(file.getPath());
			//}
			
			if (file.getName().endsWith(".class")) {
				// class files will be found under classes folder 
				// developed for windows
				if (file.getPath().indexOf("classes") == -1) {
					continue;
				}
	            String className = file.getPath().substring(file.getPath().indexOf("classes")+8,file.getPath().length()-6);
	            className = className.replace('\\', '.');
	            Class createdClass = loadClass(className);
	            classes.add(createdClass);
	            System.out.println(createdClass.getName() + " is loaded to classloader..");
			}

    	}
    }

	public void loadFromJar(String jarName) throws IOException, ClassNotFoundException {
    	JarFile jarFile = new JarFile(jarName);
        Enumeration e = jarFile.entries();
        
        while (e.hasMoreElements()) {
          JarEntry je = (JarEntry) e.nextElement();
          if(je.isDirectory() || !je.getName().endsWith(".class")){
              continue;
          }
          
          // -6 because of .class
          String className = je.getName().substring(0,je.getName().length()-6);
          className = className.replace('/', '.'); // for jars..
          Class createdClass = loadClass(className);
          classes.add(createdClass);
          System.out.println(createdClass.getName() + " is loaded to classloader..");
      }
    }
 
    public TimeMachineClassLoader(File file) throws ZipException, IOException {
        super(makeUrls(file));
    }

	public Vector<Class<?>> getClasses() {
		return classes;
	}

	public void setClasses(Vector<Class<?>> classes) {
		this.classes = classes;
	}

}